#include "listbuffer.hpp"

#include "bits.hpp"

namespace mina
{
	namespace bits
	{
		const byte * Endian::name[] = {"big_endian", "little_endian"};
		Endian::Obj Endian::obj;

		const static int SHIFT[] = {0, 8, 16, 24, 32, 40, 48, 56};

		template <>
			char byte_at<char>(uint8_t i, char val)
			{
				return (char)val;
			}
		
		template <>
			char byte_at<int8_t>(uint8_t i, int8_t val)
			{
				return (char)val;
			}
		
		template <>
			char byte_at<uint8_t>(uint8_t i, uint8_t val)
			{
				return (char)val;
			}
		
		template <>
			char byte_at<uint16_t>(uint8_t i, uint16_t val)
			{
				return (char)((val >> SHIFT[i]) & 0xff);
			}
		
		template <>
			char byte_at<int16_t>(uint8_t i, int16_t val)
			{
				return byte_at<uint16_t>(i, (uint16_t)val);
			}
		
		template <>
			char byte_at<uint32_t>(uint8_t i, uint32_t val)
			{
				return (char)((val >> SHIFT[i]) & 0xff);
			}
		
		template <>
			char byte_at<int32_t>(uint8_t i, int32_t val)
			{
				return byte_at<uint32_t>(i, (uint32_t)val);
			}
		
		template <>
			char byte_at<uint64_t>(uint8_t i, uint64_t val)
			{
				return (char)((val >> SHIFT[i]) & 0xff);
			}
		
		template <>
			char byte_at<int64_t>(uint8_t i, int64_t val)
			{
				return byte_at<uint64_t>(i, (uint64_t)val);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, char & val)
			{
				buffer.copy_out(val);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, int8_t & val)
			{
				buffer.copy_out((char&)val);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, unsigned char & val)
			{
				copy_out_b<char>(buffer, (char&)val);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, uint16_t & val)
			{
				byte ch[2];
				buffer.copy_out(ch, 2);
				val = make_uint16(ch[0], ch[1]);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, int16_t & val)
			{
				copy_out_b<uint16_t>(buffer, (uint16_t&)val);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, uint32_t & val)
			{
				byte ch[4];
				buffer.copy_out(ch, 4);
				val = make_uint32(ch[0], ch[1], ch[2], ch[3]);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, int32_t & val)
			{
				copy_out_b<uint32_t>(buffer, (uint32_t&)val);
			}
			
		template <>
			void copy_out_b(ListBuffer & buffer, uint64_t & val)
			{
				byte ch[8];
				buffer.copy_out(ch, 8);
				val = make_uint64(ch[0], ch[1], ch[2], ch[3],
									ch[4], ch[5], ch[6], ch[7]);
			}

		template <>
			void copy_out_b(ListBuffer & buffer, int64_t & val)
			{
				copy_out_b<uint64_t>(buffer, (uint64_t&)val);
			}
		
		template <>
			void copy_out_l(ListBuffer & buffer, char & val)
			{
				buffer.copy_out(val);
			}

		template <>
			void copy_out_l(ListBuffer & buffer, int8_t & val)
			{
				buffer.copy_out((char&)val);
			}

		template <>
			void copy_out_l(ListBuffer & buffer, unsigned char & val)
			{
				buffer.copy_out((char&)val);
			}

		template <>
			void copy_out_l(ListBuffer & buffer, uint16_t & val)
			{
				byte ch[2];
				buffer.copy_out(ch, 2);
				val = make_uint16(ch[0], ch[1]);
				// val = make_uint16(ch[1], ch[0]);
			}

		template <>
			void copy_out_l(ListBuffer & buffer, int16_t & val)
			{
				copy_out_l<uint16_t>(buffer, (uint16_t&)val);
			}

		template <>
			void copy_out_l(ListBuffer & buffer, uint32_t & val)
			{
				byte ch[4];
				buffer.copy_out(ch, 4);
				val = make_uint32(ch[0], ch[1], ch[2], ch[3]);
				// val = make_uint32(ch[3], ch[2], ch[1], ch[0]);
			}
		
		template <>
			void copy_out_l(ListBuffer & buffer, int32_t & val)
			{
				copy_out_l<uint32_t>(buffer, (uint32_t&)val);
			}
		
		template <>
			void copy_out_l(ListBuffer & buffer, uint64_t & val)
			{
				byte ch[8];
				buffer.copy_out(ch, 8);
				val = make_uint64(ch[0], ch[1], ch[2], ch[3],
									ch[4], ch[5], ch[6], ch[7]);
#if 0
				val = make_uint64(ch[7], ch[6], ch[5], ch[4],
									ch[3], ch[2], ch[1], ch[0]);
#endif
			}

		template <>
			void copy_out_l(ListBuffer & buffer, int64_t & val)
			{
				copy_out_l<uint64_t>(buffer, (uint64_t&)val);
			}
		
		template <>
			void copy_in_b(ListBuffer & buffer, const char & val)
			{
				buffer.copy_in(byte_at(0, val), 0);
			}

		template <>
			void copy_in_b(ListBuffer & buffer, const int8_t & val)
			{
				buffer.copy_in(byte_at(0, val), 0);
			}

		template <>
			void copy_in_b(ListBuffer & buffer, const unsigned char & val)
			{
				buffer.copy_in(byte_at(0, val), 0);
			}
		
		template <>
			void copy_in_b(ListBuffer & buffer, const uint16_t & val)
			{
				buffer.copy_in(byte_at(1, val), 0);
				buffer.copy_in(byte_at(0, val), 1);
			}

		template <>
			void copy_in_b(ListBuffer & buffer, const int16_t & val)
			{
				copy_in_b<uint16_t>(buffer, (uint16_t)val);
			}
		
		template <>
			void copy_in_b(ListBuffer & buffer, const uint32_t & val)
			{
				buffer.copy_in(byte_at(3, val), 0);
				buffer.copy_in(byte_at(2, val), 1);
				buffer.copy_in(byte_at(1, val), 2);
				buffer.copy_in(byte_at(0, val), 3);
			}
		
		template <>
			void copy_in_b(ListBuffer & buffer, const int32_t & val)
			{
				copy_in_b<uint32_t>(buffer, (uint32_t)val);
			}

		template <>
			void copy_in_b(ListBuffer & buffer, const uint64_t & val)
			{
				buffer.copy_in(byte_at(7, val), 0);
				buffer.copy_in(byte_at(6, val), 1);
				buffer.copy_in(byte_at(5, val), 2);
				buffer.copy_in(byte_at(4, val), 3);
				buffer.copy_in(byte_at(3, val), 4);
				buffer.copy_in(byte_at(2, val), 5);
				buffer.copy_in(byte_at(1, val), 6);
				buffer.copy_in(byte_at(0, val), 7);
#if 0
				buffer.copy_in(byte_at(7, val), 0);
				buffer.copy_in(byte_at(6, val), 1);
				buffer.copy_in(byte_at(5, val), 2);
				buffer.copy_in(byte_at(4, val), 3);
				buffer.copy_in(byte_at(3, val), 4);
				buffer.copy_in(byte_at(2, val), 5);
				buffer.copy_in(byte_at(1, val), 6);
				buffer.copy_in(byte_at(0, val), 7);
#endif
			}
	
		template <>
			void copy_in_b(ListBuffer & buffer, const int64_t & val)
			{
				copy_in_b<uint64_t>(buffer, (uint64_t)val);
			}
		
		template <>
			void copy_in_l(ListBuffer & buffer, const char & val)
			{
				buffer.copy_in(byte_at(0, val), 0);
			}
		
		template <>
			void copy_in_l(ListBuffer & buffer, const int8_t & val)
			{
				buffer.copy_in(byte_at(0, val), 0);
			}

		template <>
			void copy_in_l(ListBuffer & buffer, const unsigned char & val)
			{
				buffer.copy_in(byte_at(0, val), 0);
			}
		
		template <>
			void copy_in_l(ListBuffer & buffer, const uint16_t & val)
			{
				buffer.copy_in(byte_at(0, val), 1);
				buffer.copy_in(byte_at(1, val), 0);
#if 0
				buffer.copy_in(byte_at(0, val), 0);
				buffer.copy_in(byte_at(1, val), 1);
#endif
			}
		
		template <>
			void copy_in_l(ListBuffer & buffer, const int16_t & val)
			{
				copy_in_l<uint16_t>(buffer, (uint16_t)val);
			}

		template <>
			void copy_in_l(ListBuffer & buffer, const uint32_t & val)
			{
				buffer.copy_in(byte_at(0, val), 3);
				buffer.copy_in(byte_at(1, val), 2);
				buffer.copy_in(byte_at(2, val), 1);
				buffer.copy_in(byte_at(3, val), 0);
#if 0
				buffer.copy_in(byte_at(0, val), 0);
				buffer.copy_in(byte_at(1, val), 1);
				buffer.copy_in(byte_at(2, val), 2);
				buffer.copy_in(byte_at(3, val), 3);
#endif
			}

		template <>
			void copy_in_l(ListBuffer & buffer, const int32_t & val)
			{
				copy_in_l<uint32_t>(buffer, (uint32_t)val);
			}
		
		template <>
			void copy_in_l(ListBuffer & buffer, const uint64_t & val)
			{
				buffer.copy_in(byte_at(0, val), 7);
				buffer.copy_in(byte_at(1, val), 6);
				buffer.copy_in(byte_at(2, val), 5);
				buffer.copy_in(byte_at(3, val), 4);
				buffer.copy_in(byte_at(4, val), 3);
				buffer.copy_in(byte_at(5, val), 2);
				buffer.copy_in(byte_at(6, val), 1);
				buffer.copy_in(byte_at(7, val), 0);
#if 0
				buffer.copy_in(byte_at(0, val), 0);
				buffer.copy_in(byte_at(1, val), 1);
				buffer.copy_in(byte_at(2, val), 2);
				buffer.copy_in(byte_at(3, val), 3);
				buffer.copy_in(byte_at(4, val), 4);
				buffer.copy_in(byte_at(5, val), 5);
				buffer.copy_in(byte_at(6, val), 6);
				buffer.copy_in(byte_at(7, val), 7);
#endif
			}

		template <>
			void copy_in_l(ListBuffer & buffer, const int64_t & val)
			{
				copy_in_l<uint64_t>(buffer, (uint64_t)val);
			}
	}
}

